# -*- coding: utf-8 -*-
from collections import defaultdict

from flask import request, jsonify, abort, current_app
from mongoengine import Q
import elasticsearch_dsl as E

from app.models import Product, Classify, Destination, Mtu, KV
from app.constants import MTU_TYPE
from app.controllers import get_product_infos, get_mtu_comments
from app import redis_keys as rk
from app.forms import check_start_count
from app.elastic_models import ProductDoc


@current_app.route("/vacation/featured/")
def featured():
    """自由行banner 推荐

    #### 请求参数

    参数名 | 必须 | 类型 | 说明
    ---- | ---- | ---- | ----
    无 ｜ 无 | 无 | 无

    #### 返回结果
    {
        status: 0,
        message: xxxxx,
        data: {
            "elements": [
                {
                  "image_url": "http://image_url",
                  "html_url": "http://html_url"
                },
                ...
            ]
        }
    }
    """
    return jsonify({
        'status': 0,
        'message': 'success',
        'data': KV.get(rk.VACATION_ACTIVITIES) or {},
    })


@current_app.route("/vacation/classify/")
def classify():
    """产品分类筛选

    #### 请求参数

    参数名 | 必须 | 类型 | 说明
    ---- | ---- | ---- | ----
    无 ｜ 无 ｜ 无 ｜ 无

    #### 返回结果
    {
        classifies: [
            'id': 1,
            'name': '一日游',
            'name_en': 'tour'
            ],
        ],
    }
    """
    classifies = Classify.objects(is_active=True)
    classify_list = [{'id': 'all', 'name': u'全部', 'name_en': 'all'}]
    for classify in classifies:
        classify_dict = {
            'id': str(classify.pk),
            'name': classify.name,
            'name_en': classify.name_en,
        }
        classify_list.append(classify_dict)
    return jsonify({
        'classifies': classify_list,
    })


@current_app.route("/vacation/destinations/")
def destinations():
    """产品目的地筛选

    #### 请求参数

    参数名 | 必须 | 类型 | 说明
    ---- | ---- | ---- | ----
    无 ｜ 无 ｜ 无 ｜ 无

    #### 返回结果
    {
        localities: [
            'id': 1,
            'name': 泰国,
            'destinations': [
                'id': destination.pk,
                'name': 曼谷,
            ],
        ],
    }
    """
    destinations = set([p.destination for p in Product.objects(is_active=True, published=True)])
    items = [{'id': 'all', 'name': u'全部', 'destinations': []}]

    locality_by_id = {}
    lid2dests = defaultdict(list)
    for dst in destinations:
        lid = dst.locality.id
        lid2dests[lid].append(dst)
        locality_by_id[lid] = dst.locality
    for lid, dests in lid2dests.items():
        item = {
            'id': str(lid),
            'name': locality_by_id[lid].name,
            'destinations': [{'id': str(dest.pk), 'name': dest.name} for dest in dests if dest.name != u'泰国'],
        }
        items.append(item)
    return jsonify({
        'localities': items,
    })


@current_app.route("/vacation/products/")
# @pre_check_start_count()
def products():
    """
    #### 请求参数

    参数名 | 必须 | 类型 | 说明
    ---- | ---- | ---- | ----
    start | N | int | 行程列表起始值，默认为0。
    count | N | int | 取回行程条数，默认为20。
    destination_id | N | int | 目的地id
    classify_id | N | int | 分类id

    #### 返回结果
    """
    device_id = request.headers.get('HTTP_VACATION_DEVICE_ID') or request.args.get('device_id')

    # 获取目的地信息
    # start, count = request.breadtrip.start_count
    start, count = check_start_count(request)

    destination_id = request.args.get('destination_id')
    destination = Destination.objects(pk=destination_id).first() if destination_id else None
    # classify_id = request.args.get('classify_id', 'all')

    params = {}
    # if classify_id:
    #     params['classify__id'] = classify_id

    if destination:
        # 国家需要另外添加的产品id
        append_ids = KV.get(rk.LOCALITY_APPEND_PRODUCTS).get(destination.locality.id, [])

        mtus = Mtu.objects(published=True,
                           target_type=MTU_TYPE.PRODUCT, destination=destination)
        params.update(pk__in=mtus)
        products = Product.objects(**params)\
            .filter(pk__nin=append_ids)[start:start + count + 1]

        # 分页页码
        next_start = start + count if products.count() > count else None

        # 第一页的话加入保险等特殊产品
        products = products[:count]
        if start == 0:
            _products = Product.objects(pk__in=append_ids)
            for product in _products:
                products.insert(2, product)
    else:
        # 查看全部地区产品时策略
        recommend_ids = KV.get(rk.VACATION_FEATURE_PRODUCTS) or []
        # recommend_ids = []
        # for recommend_id in recommend_ids:
        #     if str(recommend_id).isdigit():
        #         product_ids.append(recommend_id)

        if start == 0 and recommend_ids:
            products = Product.objects(pk__in=recommend_ids)
            _products = []
            if len(products) < count:
                _products = Product.objects(**params).\
                    filter(pk__nin=recommend_ids).order_by('last_modified')[:count - len(products)]
            products = list(products) + list(_products)
            next_start = count
        else:
            k = len(recommend_ids)
            start = start - k if start > k else 0

            products = Product.objects(**params)\
                .filter(pk__nin=recommend_ids).order_by('last_modified')[start:start + count + 1]
            next_start = start + k + \
                count if products.count() > count else None
            products = products[:count]

    items = get_product_infos(products, device_id=device_id)
    return jsonify({
        'items': items,
        'next_start': next_start,
    })


@current_app.route("/vacation/<path:mtu>/<obj_id>/detail/")
@current_app.route("/vacation/product/<obj_id>/detail/")
def detail(obj_id, mtu=None):
    """旅行产品详情
    poi点附近的pois

    #### 请求参数

    参数名 | 必须 | 类型 | 说明
    ---- | ---- | ---- | ----
    无 | 无 | 无 | 无

    #### 返回结果
    """
    # id_decrypt?

    # 非mtu版本接口
    if not mtu:
        product_id = obj_id
        product = Product.objects(is_active=True, published=True, pk=product_id).first()
        return jsonify(product.get_api_info(request=request))
    else:
        mtu_id = obj_id
        mtu = Mtu.objects(published=True, pk=mtu_id).first()
        if mtu:
            ret = get_mtu_comments(mtu, start=0, count=1, request=request)
            info = mtu.get_info(with_small_covers=True)
            info['tips_count'] = ret.get('total_count')
            info['tip'] = ret.get('tips')[0] if ret.get('tips') else None
            # 获取问答数量
            info['dialogs_count'] = mtu.get_dialog_count()
            return jsonify(info)
        abort(404)


@current_app.route("/vacation/product/index/")
def index():
    """旅行产品首页(含酒店)

    #### 请求参数

    参数名 | 必须 | 类型 | 说明
    ---- | ---- | ---- | ----
    start | N | int | 产品列表起始值，默认为0。
    count | N | int | 产品列表条数，默认为20。

    #### 返回结果
    """
    device_id = request.headers.get('HTTP_VACATION_DEVICE_ID') or request.args.get('device_id')

    # 获取目的地信息
    start, count = check_start_count(request)

    # 获取推荐产品ID列表
    recommend_ids = KV.get(rk.VACATION_FEATURE_PRODUCTS) or []

    # hotel_info = KV.get(rk.VACATION_HOTEL_RECOMMEND) or {}
    recommend_info = []
    # product_ids = []

    # 推荐产品中周边游产品的id
    # for recommend_id in recommend_ids:
    #     if str(recommend_id).isdigit():
    #         product_ids.append(recommend_id)

    if start == 0 and recommend_ids:
        # 首页(第一次请求) 且有推荐产品
        # print 'recommend_ids', recommend_ids
        for recommend_id in recommend_ids:
            # 周边游产品
            # product_ids.append(recommend_id)
            product = Product.objects(pk=recommend_id, published=True, is_active=True).first()

            if product:
                recommend_info.append(product)
            # else:
            #     # 酒店
            #     hotel = hotel_info.get(recommend_id)
            #     if hotel:
            #         recommend_info.append(hotel)
        _products = []
        if len(recommend_info) < count:
            # 如果推荐产品数量不足，用周边游产品补齐
            _products = Product.objects(published=True, is_active=True, pk__nin=recommend_ids).\
                            order_by('last_modified')[:count - len(recommend_info)]
        products = list(recommend_info) + list(_products)
        next_start = count
    else:
        # 加载更多，或首页无推荐数据
        # total为推荐的产品数量
        # total = len(product_ids)
        total = len(recommend_ids)

        if start > total:
            start = start - total
        else:
            # 无推荐数据
            start = 0

        products = Product.objects(published=True, is_active=True, pk__nin=recommend_ids).\
            order_by('last_modified')[start:start + count + 1]

        next_start = start + total + \
            count if products.count() > count else None
        products = products[:count]

    items = get_product_infos(products, device_id=device_id)

    return jsonify({
        'items': items,     # 每周精选
        'next_start': next_start,
    })


@current_app.route("/vacation/product/search/")
def search():
    """旅行产品搜索
    #### 请求参数

    参数名 | 必须 | 类型 | 说明
    ---- | ---- | ---- | ----
    start | N | int | 行程列表起始值，默认为0。
    count | N | int | 取回行程条数，默认为20。
    destination_id | N | int | 目的地id
    keyword | 产品搜索

    #### 返回结果
    """
    device_id = request.headers.get('HTTP_VACATION_DEVICE_ID') or request.args.get('device_id')

    start, count = check_start_count(request)
    # 获取目的地信息
    destination_id = request.args.get('destination_id')
    classify_id = request.args.get('classify_id')
    keyword = request.args.get('keyword')

    condition = E.Q('term', published=True) & E.Q('term', is_active=True)
    if classify_id:
        condition = condition & E.Q('term', classify_id=classify_id)
    if destination_id:
        condition = condition & E.Q('term', destination_id=destination_id)
    if keyword:
        condition = condition & E.Q('query_string', query=keyword, default_field='name')
        # condition = condition & E.Q('term', name=keyword)

    s = ProductDoc.search().query(condition).sort('-last_modified')[start: start+count]
    hits = s.execute()
    next_start = start+count if len(hits) == count else None
    product_ids = [hit._id for hit in hits]
    # 查看全部地区产品时策略
    products = Product.objects(pk__in=product_ids)

    items = get_product_infos(
        products, device_id=device_id)
    # print 'len', len(products), len(items)
    return jsonify({
        'items': items,
        'next_start': next_start,
    })
